package com.microservice.skeleton.upms.config;

import capital.scalable.restdocs.jsondoclet.ClassDocumentation;
import com.sun.javadoc.*;

import java.util.HashMap;
import java.util.Map;

import static capital.scalable.restdocs.jsondoclet.DocletUtils.cleanupTagName;
import static org.apache.commons.lang3.StringUtils.trimToEmpty;

/**
 * @author: lijin
 * @date: 2018年10月31日
 */
public class ClassJavadoc {
    private String comment;
    private Map<String, FieldJavadoc> fields = new HashMap<>();
    private Map<String, MethodJavadoc> methods = new HashMap<>();

    public static ClassJavadoc fromClassDoc(ClassDoc classDoc) {
        ClassJavadoc cd = new ClassJavadoc();
        cd.setComment(classDoc.commentText());
        for (FieldDoc fieldDoc : classDoc.fields(false)) {
            cd.addField(fieldDoc);
        }
        for (MethodDoc methodDoc : classDoc.methods(false)) {
            cd.addMethod(methodDoc);
        }
        return cd;
    }
    private void setComment(String comment) {
        this.comment = comment;
    }

    private void addField(FieldDoc fieldDoc) {
        this.fields.put(fieldDoc.name(), FieldJavadoc.fromFieldDoc(fieldDoc));
    }

    private void addMethod(MethodDoc methodDoc) {
        this.methods.put(methodDoc.name(), MethodJavadoc.fromMethodDoc(methodDoc));
    }


    public String getClassComment() {
        return comment;
    }

    public String getFieldComment(String fieldName) {
        FieldJavadoc fieldJavadoc = fields.get(fieldName);
        if (fieldJavadoc != null) {
            return trimToEmpty(fieldJavadoc.getComment());
        } else {
            return "";
        }
    }

    public String getMethodComment(String methodName) {
        MethodJavadoc methodJavadoc = methods.get(methodName);
        if (methodJavadoc != null) {
            return trimToEmpty(methodJavadoc.getComment());
        } else {
            return "";
        }
    }

    public String getMethodParameterComment(String methodName, String parameterName) {
        MethodJavadoc methodJavadoc = methods.get(methodName);
        if (methodJavadoc != null) {
            return trimToEmpty(methodJavadoc.getParameterComment(parameterName));
        } else {
            return "";
        }
    }

    public String getMethodTag(String javaMethodName, String tagName) {
        MethodJavadoc methodJavadoc = methods.get(javaMethodName);
        if (methodJavadoc != null) {
            return trimToEmpty(methodJavadoc.getTag(tagName));
        } else {
            return "";
        }
    }

    public String getFieldTag(String javaFieldName, String tagName) {
        FieldJavadoc fieldJavadoc = fields.get(javaFieldName);
        if (fieldJavadoc != null) {
            return trimToEmpty(fieldJavadoc.getTag(tagName));
        } else {
            return "";
        }
    }

    static class MethodJavadoc {
        private String comment;
        private Map<String, String> parameters = new HashMap<>();
        private Map<String, String> tags = new HashMap<>();

        public String getComment() {
            return comment;
        }

        public String getParameterComment(String parameterName) {
            return parameters.get(parameterName);
        }

        public String getTag(String tagName) {
            return tags.get(tagName);
        }

        public static MethodJavadoc fromMethodDoc(MethodDoc methodDoc) {
            MethodJavadoc md = new MethodJavadoc();
            md.comment = methodDoc.commentText();

            for (Tag tag : methodDoc.tags()) {
                if (tag instanceof ParamTag) {
                    ParamTag paramTag = (ParamTag) tag;
                    md.parameters.put(paramTag.parameterName(), paramTag.parameterComment());
                } else {
                    md.tags.put(cleanupTagName(tag.name()), tag.text());
                }
            }

            return md;
        }
    }

    static class FieldJavadoc {
        private String comment;
        private Map<String, String> tags = new HashMap<>();

        public String getComment() {
            return comment;
        }

        public String getTag(String tagName) {
            return tags.get(tagName);
        }

        public static FieldJavadoc fromFieldDoc(FieldDoc fieldDoc) {
            FieldJavadoc fd = new FieldJavadoc();
            fd.comment = fieldDoc.commentText();

            for (Tag tag : fieldDoc.tags()) {
                fd.tags.put(cleanupTagName(tag.name()), tag.text());
            }

            return fd;
        }
    }
}
